﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;

namespace RCSnake
	{
	class Snake
		{

		/*---------------------------------------------*\
		|*                 Attributs                   *|
		\*---------------------------------------------*/
		private int m_speedX;
		private int m_speedY;
		private int m_headDirectionX;
		private int m_headDirectionY;
		private int m_cptSmallFood;
		private int m_cptBigFood;
		private Area m_area;
		private List<BodyBlock> m_listBodyBlock;

		/*---------------------------------------------*\
		|*                Constructeur                 *|
		\*---------------------------------------------*/
		public Snake(Area area, Size size, Point position)
			{
			m_speedX = Parameters.DEFAULT_START_SPEED;
			m_speedY = Parameters.DEFAULT_START_SPEED;
			m_headDirectionX = (int)Direction.POSITIVE;
			m_headDirectionY = (int)Direction.NULL;
			m_cptSmallFood = 0;
			m_cptBigFood = 0;
			m_area = area;
			m_listBodyBlock = new List<BodyBlock>();
			this.reset();
			}

		/*---------------------------------------------*\
		|*               Methodes public               *|
		\*---------------------------------------------*/
		public void move()
			{
			BodyBlock[] tabBody = new BodyBlock[m_listBodyBlock.Count];
			int i = 0;
			foreach(BodyBlock body in m_listBodyBlock)
				{
				tabBody[i] = body;

				body.oldDirectionX = body.directionX;
				body.oldDirectionY = body.directionY;

				if(i == 0)
					{
					body.directionX = m_headDirectionX;
					body.directionY = m_headDirectionY;
					body.changePosition(body.directionX * m_speedX, body.directionY * m_speedY);
					}
				else
					{
					body.directionX = tabBody[i - 1].oldDirectionX;
					body.directionY = tabBody[i - 1].oldDirectionY;
					body.changePosition(body.directionX * m_speedX, body.directionY * m_speedY);

					}
				++i;
				}
			}

		public void grow()
			{
			BodyBlock lastBody = m_listBodyBlock.Last();
			Point position = new Point(lastBody.position.X, lastBody.position.Y);

			if(lastBody.directionX == (int)Direction.POSITIVE && lastBody.directionY == (int)Direction.NULL)
				{
				position.X -= lastBody.size.Width;
				}
			else if(lastBody.directionX == (int)Direction.NEGATIVE && lastBody.directionY == (int)Direction.NULL)
				{
				position.X += lastBody.size.Width;
				}
			else if(lastBody.directionX == (int)Direction.NULL && lastBody.directionY == (int)Direction.POSITIVE)
				{
				position.Y -= lastBody.size.Height;
				}
			else
				{
				position.Y += lastBody.size.Height;
				}

			BodyBlock newBody = new BodyBlock(m_area, this, lastBody, lastBody.size, position);
			m_listBodyBlock.Add(newBody);
			}

		public void incrementSmallFood()
			{
			m_cptSmallFood++;
			}

		public void incrementBigFood()
			{
			m_cptBigFood++;
			}

		public void testClash()
			{
			BodyBlock firstBody = m_listBodyBlock.First();
			SnakeEventArgs e = new SnakeEventArgs();

			//Test si la tête du serpent touche un mur. Si c'est le cas, un événement est déclenché
			if(!m_area.border.rectangleBorder.IntersectsWith(firstBody.rectangleBlock))
				{
				signal_clashed(this, e);
				return;
				}

			//test si le serpent se touche lui-même
			int i = 0;
			foreach(BodyBlock body in m_listBodyBlock)
				{
				if(i != 0)
					{
					if(body.rectangleBlock.Contains(firstBody.rectangleBlock))
						{
						signal_clashed(this, e);
						return;
						}
					}
				++i;
				}
			}

		public void testEat()
			{
			BodyBlock firstBlock = m_listBodyBlock.First();
			SnakeEventArgs e = new SnakeEventArgs();
			if(m_area.smallFood.rectangleBlock.IntersectsWith(firstBlock.rectangleBlock))
				{
				this.signal_smallFoodEaten(this, e);
				}
			else if(m_area.bigFood.rectangleBlock.IntersectsWith(firstBlock.rectangleBlock))
				{
				this.signal_bigFoodEaten(this, e);
				}
			}

		public void reset()
			{
			m_speedX = Parameters.DEFAULT_START_SPEED;
			m_speedY = Parameters.DEFAULT_START_SPEED;
			m_headDirectionX = (int)Direction.POSITIVE;
			m_headDirectionY = (int)Direction.NULL;
			m_listBodyBlock.Clear();
			m_listBodyBlock.Add(new Head(m_area, this, null, new Size(Parameters.DEFAULT_SNAKE_SIZE, Parameters.DEFAULT_SNAKE_SIZE), new Point(Parameters.DEFAULT_POSX_START, Parameters.DEFAULT_POSY_START)));
			m_cptSmallFood = 0;
			m_cptBigFood = 0;

			this.grow();
			this.grow();
			this.grow();
			this.grow();

			}
		/*---------------------*\
		|*      get / set      *|
		\*---------------------*/
		public int speedX
			{
			get { return m_speedX; }
			}

		public int speedDX
			{
			set { m_speedX += value; }
			}

		public int speedY
			{
			get { return m_speedY; }
			}

		public int speedDY
			{
			set { m_speedY += value; }
			}

		public int directionX
			{
			get { return m_headDirectionX; }
			set { m_headDirectionX = value; }
			}

		public int directionY
			{
			get { return m_headDirectionY; }
			set { m_headDirectionY = value; }
			}

		public int nbBigFoodEaten
			{
			get { return m_cptBigFood; }
			}

		public int nbSmallFoodEaten
			{
			get { return m_cptSmallFood; }
			}

		public List<BodyBlock> listBodyBlocks
			{
			get { return m_listBodyBlock; }
			}

		internal Area Area
			{
			get
				{
				throw new System.NotImplementedException();
				}
			set
				{
				}
			}

		/*---------------------*\
		|*        event        *|
		\*---------------------*/
		public delegate void clashEventHandler(object sender, SnakeEventArgs e);
		public delegate void eatEventHandler(object sender, SnakeEventArgs e);
		public event clashEventHandler signal_clashed;
		public event eatEventHandler signal_smallFoodEaten;
		public event eatEventHandler signal_bigFoodEaten;
		}
	}
